import functools
import os

from fastapi import FastAPI
from sqlalchemy.ext.asyncio import AsyncSession

from recruit.adapter.database.db import (
    create_async_session_maker,
    create_async_session,
)
from recruit.adapter.database.gateway.user_gateway import UserGateway
from recruit.adapter.di import init_dependencies, new_uow, new_user_gateway
from recruit.adapter.stubs.user import StubUserGateway
from recruit.application.protocols import UoW


async def get_async_session(app: FastAPI) -> AsyncSession:
    async for async_session in app.dependency_overrides[AsyncSession]():
        return async_session


def change_db(app: FastAPI, db_url: str):
    session_maker = create_async_session_maker(db_url)
    app.dependency_overrides[AsyncSession] = functools.partial(
        create_async_session,
        session_maker
    )


async def test_init_dependencies(
        create_app: FastAPI,
        set_environ: None,
) -> None:
    app = create_app
    init_dependencies(app)
    keys = (AsyncSession, UoW,)
    for key in keys:
        assert app.dependency_overrides.get(key)
    change_db(app, os.getenv('DB_URI'))
    async_session = await get_async_session(app)
    assert isinstance(async_session, AsyncSession)


async def test_new_uow(
        create_app: FastAPI,
        set_environ: None
) -> None:
    app = create_app
    init_dependencies(app)
    change_db(app, os.getenv('DB_URI'))
    async_session = await get_async_session(app)
    assert isinstance(new_uow(async_session), AsyncSession)


async def test_new_user_gateway(
        create_app: FastAPI,
        set_environ: None
) -> None:
    app = create_app
    init_dependencies(app)
    change_db(app, os.getenv('DB_URI'))
    async_session = await get_async_session(app)
    user_gateway = next(new_user_gateway(async_session))
    assert isinstance(user_gateway, StubUserGateway)
    assert isinstance(user_gateway, UserGateway)
